package com.zhangh.summer.admin.biz.user.impl;

import com.zhangh.summer.admin.biz.org.OrgBiz;
import com.zhangh.summer.admin.biz.user.UserBiz;
import com.zhangh.summer.admin.model.bo.*;
import com.zhangh.summer.admin.model.po.*;
import com.zhangh.summer.admin.model.enums.UserTypeEnum;

import com.zhangh.summer.admin.support.ds.common.MixedDS;
import com.zhangh.summer.admin.support.ds.common.pager.DataPager;
import com.zhangh.summer.admin.support.ds.common.pager.Pager;
import com.zhangh.summer.admin.support.exception.BizException;
import com.zhangh.summer.admin.support.id.IdGen;
import com.zhangh.summer.admin.support.session.SysSession;
import com.zhangh.summer.admin.support.utils.BeanGenerator;
import com.zhangh.summer.admin.support.utils.MD5Util;
import com.zhangh.summer.admin.support.utils.UUIDGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description: TODO
 * @author: zhanghui  zhanghlucky@163.com
 * @create: 2021-09-28 22:34
 **/
@Service
@Slf4j
public class UserBizImpl implements UserBiz {
    @Resource
    private MixedDS mixedDS;
    @Autowired
    private IdGen idGen;
    @Autowired
    private OrgBiz orgBiz;

    @Override
    public DataPager<UserBO> getUserDataPager(UserQuery query, Pager pager) {
        if (query.getOrgID()!=null&&query.getOrgID()!=0L){
            List<Long> orgIDS=orgBiz.getOrgIDTreeList(query.getOrgID());
            query.setOrgIDS(orgIDS);
        }
        DataPager<UserBO> dataPager=this.mixedDS.txDs().mapper("UserMapper")
                .selectDataPager("selectUser",query,pager);
        return dataPager;
    }

    @Override
    public UserBO getUserBO(Long id) {
        if (id>0){
            AdUserPO adUserPO=this.mixedDS.txDs().mapper().selectByPrimaryKey(AdUserPO.class,id);
            UserBO userBO= BeanGenerator.copy(adUserPO,UserBO.class);
            List<Long> checkedRoleIDList=this.getUserRoleIDList(id);
            List<Long> checkedAuthIDList=this.getUserAuthIDList(id);

            AdRolePOExample rolePOExample=new AdRolePOExample();
            rolePOExample.createCriteria().andIsEnableEqualTo(true);
            rolePOExample.setOrderByClause("createTime asc");
            List<AdRolePO> rolePOS=this.mixedDS.txDs().mapper().selectByExample(rolePOExample);

            List<Long> roleIDList=new ArrayList<>();
            List<RoleBO> roleList=rolePOS.stream().map(item->{
                RoleBO roleBO=BeanGenerator.copy(item,RoleBO.class);
                boolean isChecked=checkedRoleIDList.stream().anyMatch(roleID->roleID.equals(item.getId()));
                roleBO.setChecked(isChecked);
                if (isChecked){
                    roleIDList.add(roleBO.getId());
                }
                return roleBO;
            }).collect(Collectors.toList());
            userBO.setRoleList(roleList);
            userBO.setRoleIDList(roleIDList);

            AdAuthPOExample authPOExample=new AdAuthPOExample();
            authPOExample.createCriteria().andIsEnableEqualTo(true);
            authPOExample.setOrderByClause("createTime asc");
            List<AdAuthPO> authPOS=this.mixedDS.txDs().mapper().selectByExample(authPOExample);

            List<Long> authIDList=new ArrayList<>();
            List<AuthBO> authList=authPOS.stream().map(item->{
                AuthBO authBO= BeanGenerator.copy(item,AuthBO.class);
                boolean isChecked=checkedAuthIDList.stream().anyMatch(authID->authID.equals(item.getId()));
                authBO.setChecked(isChecked);
                if (isChecked){
                    authIDList.add(authBO.getId());
                }
                return authBO;
            }).collect(Collectors.toList());
            userBO.setAuthList(authList);
            userBO.setAuthIDList(authIDList);
            return userBO;
        }else{//id=0 返回个新用户对象
            UserBO userBO= new UserBO();
            BeanGenerator.fillNull(userBO);
            userBO.setIsEnable(true);
            userBO.setUserType(UserTypeEnum.NORMAL.getValue());

            AdRolePOExample rolePOExample=new AdRolePOExample();
            rolePOExample.createCriteria().andIsEnableEqualTo(true);
            rolePOExample.setOrderByClause("createTime asc");
            List<AdRolePO> rolePOS=this.mixedDS.txDs().mapper().selectByExample(rolePOExample);

            List<RoleBO> roleList=rolePOS.stream().map(item->{
                RoleBO roleBO=BeanGenerator.copy(item,RoleBO.class);
                roleBO.setChecked(false);
                return roleBO;
            }).collect(Collectors.toList());
            userBO.setRoleList(roleList);
            userBO.setAuthIDList(new ArrayList<>());

            AdAuthPOExample authPOExample=new AdAuthPOExample();
            authPOExample.createCriteria().andIsEnableEqualTo(true);
            authPOExample.setOrderByClause("createTime asc");
            List<AdAuthPO> authPOS=this.mixedDS.txDs().mapper().selectByExample(authPOExample);

            List<AuthBO> authList=authPOS.stream().map(item->{
                AuthBO authBO= BeanGenerator.copy(item,AuthBO.class);
                authBO.setChecked(false);
                return authBO;
            }).collect(Collectors.toList());
            userBO.setAuthList(authList);
            userBO.setRoleIDList(new ArrayList<>());
            return userBO;
        }

    }

    @Override
    @Transactional
    public long saveUser(UserBO userBO) {
        AdUserPO adUserPO=BeanGenerator.copy(userBO,AdUserPO.class);
        adUserPO.setId(idGen.getID());
        adUserPO.setCreateBy(SysSession.getUser().getLoginName());
        adUserPO.setCreateTime(new Date());
        adUserPO.setUpdateBy(SysSession.getUser().getLoginName());
        adUserPO.setUpdateTime(new Date());
        adUserPO.setIsDel(false);
        String salt= UUIDGenerator.random32UUID();
        adUserPO.setSalt(salt);
        String loginPwd=genPwd(userBO.getLoginPwd(),salt);
        adUserPO.setLoginPwd(loginPwd);
        int c1=this.mixedDS.txDs().mapper().insert(adUserPO);
        log.info("保存用户 id {}",adUserPO.getId());

        //List<AdUserRolePO> originalUserRoleList=this.mixedDS.txDs().mapper().selectByExample();
        List<AdUserRolePO> userRoleInsertList=new ArrayList<>();
        List<Long> roleIDS=userBO.getRoleIDList();
        for (Long roleID : roleIDS) {
            AdUserRolePO adUserRolePO=new AdUserRolePO();
            adUserRolePO.setId(idGen.getID());
            adUserRolePO.setRoleID(roleID);
            adUserRolePO.setUserID(adUserPO.getId());
            userRoleInsertList.add(adUserRolePO);
        }
        if (userRoleInsertList.size()>0){
            int c2=this.mixedDS.txDs().mapper().batchInsert(userRoleInsertList,AdUserRolePO.class);
            log.info("保存用户角色 size {}",c2);
        }

        List<AdUserAuthPO> userAuthInsertList=new ArrayList<>();
        List<Long> authIDS= userBO.getAuthIDList();
        for (Long authID : authIDS) {
            AdUserAuthPO adUserAuthPO=new AdUserAuthPO();
            adUserAuthPO.setId(idGen.getID());
            adUserAuthPO.setAuthID(authID);
            adUserAuthPO.setUserID(adUserPO.getId());
            userAuthInsertList.add(adUserAuthPO);
        }
        if (userAuthInsertList.size()>0){
            int c3=this.mixedDS.txDs().mapper().batchInsert(userAuthInsertList,AdUserAuthPO.class);
            log.info("保存用户权限 size {}",c3);
        }
        return c1;
    }

    @Override
    @Transactional
    public int updateUser(UserBO userBO) {
        AdUserPO adUserPO=BeanGenerator.copy(userBO,AdUserPO.class);
        adUserPO.setUpdateBy(SysSession.getUser().getLoginName());
        adUserPO.setUpdateTime(new Date());

        if (StringUtils.isNotBlank(userBO.getLoginPwd())){
            String loginPwd=genPwd(userBO.getLoginPwd(),userBO.getSalt());
            adUserPO.setLoginPwd(loginPwd);
        }else{
            AdUserPO originalUser=this.mixedDS.txDs().mapper().selectByPrimaryKey(AdUserPO.class,userBO.getId());
            adUserPO.setLoginPwd(originalUser.getLoginPwd());
        }
        int c1=this.mixedDS.txDs().mapper().updateByPrimaryKey(adUserPO);
        log.info("更新用户 id {}",adUserPO.getId());

        AdUserRolePOExample userRolePOExample=new AdUserRolePOExample();
        userRolePOExample.createCriteria().andUserIDEqualTo(adUserPO.getId());
        List<AdUserRolePO> originalUserRoleList=this.mixedDS.txDs().mapper().selectByExample(userRolePOExample);
        List<Long> originalRoleIDS=originalUserRoleList.stream().map(AdUserRolePO::getRoleID).collect(Collectors.toList());
        List<Long> roleIDS=userBO.getRoleIDList();

        List<Long> deleteRoleIDS= originalRoleIDS.stream()
                .filter(roleID -> !roleIDS.contains(roleID))
                .collect(Collectors.toList());
        if (deleteRoleIDS.size()>0){
            userRolePOExample.clear();
            userRolePOExample.createCriteria()
                    .andUserIDEqualTo(userBO.getId())
                    .andRoleIDIn(deleteRoleIDS);
            int c3=this.mixedDS.txDs().mapper().deleteByExample(userRolePOExample);
            log.info("删除用户角色 size {}",c3);
        }

        List<AdUserRolePO> userRoleInsertList= roleIDS.stream()
                .filter(roleID -> !originalRoleIDS.contains(roleID))
                .collect(Collectors.toList()).stream().map(roleID->{
                    AdUserRolePO adUserRolePO=new AdUserRolePO();
                    adUserRolePO.setId(idGen.getID());
                    adUserRolePO.setRoleID(roleID);
                    adUserRolePO.setUserID(adUserPO.getId());
                    return adUserRolePO;
                }).collect(Collectors.toList());

        if (userRoleInsertList.size()>0){
            int c2=this.mixedDS.txDs().mapper().batchInsert(userRoleInsertList,AdUserRolePO.class);
            log.info("保存用户角色 size {}",c2);
        }

        AdUserAuthPOExample userAuthPOExample=new AdUserAuthPOExample();
        userAuthPOExample.createCriteria().andUserIDEqualTo(adUserPO.getId());
        List<AdUserAuthPO> originalUserAuthList=this.mixedDS.txDs().mapper().selectByExample(userAuthPOExample);
        List<Long> originalAuthIDS=originalUserAuthList.stream().map(AdUserAuthPO::getAuthID).collect(Collectors.toList());
        List<Long> authIDS=userBO.getAuthIDList();

        List<Long> deleteAuthIDList= originalAuthIDS.stream().filter(oriAuthID -> !authIDS.contains(oriAuthID)).collect(Collectors.toList());
        if (deleteAuthIDList.size()>0){
            userAuthPOExample.clear();
            userAuthPOExample.createCriteria()
                    .andUserIDEqualTo(userBO.getId())
                    .andAuthIDIn(deleteAuthIDList);
            int c4=this.mixedDS.txDs().mapper().deleteByExample(userAuthPOExample);
            log.info("删除用户权限 size {}",c4);
        }

        List<AdUserAuthPO> userAuthInsertList= authIDS.stream()
                .filter(authID -> !originalAuthIDS.contains(authID))
                .collect(Collectors.toList())
                .stream().map(authID->{
                    AdUserAuthPO adUserAuthPO=new AdUserAuthPO();
                    adUserAuthPO.setId(idGen.getID());
                    adUserAuthPO.setAuthID(authID);
                    adUserAuthPO.setUserID(adUserPO.getId());
                    return adUserAuthPO;
                }).collect(Collectors.toList());
        if (userAuthInsertList.size()>0){
            int c5=this.mixedDS.txDs().mapper().batchInsert(userAuthInsertList,AdUserAuthPO.class);
            log.info("保存用户权限 size {}",c5);
        }
        return c1;
    }

    @Override
    @Transactional
    public int deleteUser(Long id) {
        AdUserPO adUserPO=new AdUserPO();
        adUserPO.setId(id);
        adUserPO.setIsDel(true);
        int c1=this.mixedDS.txDs().mapper().updateByPrimaryKeySelective(adUserPO);
        log.info("逻辑删除 用户 id {}",adUserPO.getId());
        //删除用户权限
        AdUserAuthPOExample userAuthPOExample=new AdUserAuthPOExample();
        userAuthPOExample.createCriteria().andUserIDEqualTo(id);
        int c2=this.mixedDS.txDs().mapper().deleteByExample(userAuthPOExample);
        log.info("删除用户权限 size {}",c2);
        //删除用户角色
        AdUserRolePOExample userRolePOExample=new AdUserRolePOExample();
        userRolePOExample.createCriteria().andUserIDEqualTo(id);
        int c3=this.mixedDS.txDs().mapper().deleteByExample(userRolePOExample);
        log.info("删除用户角色 size {}",c3);
        return c1;
    }

    @Override
    public int updatePwd(UserBO userBO) {
        AdUserPO originalUser=this.mixedDS.txDs().mapper().selectByPrimaryKey(AdUserPO.class,userBO.getId());
        String loginPwd=this.genPwd(userBO.getLoginPwd(),originalUser.getSalt());
        if (!originalUser.getLoginPwd().equals(loginPwd)){
            log.error("用户密码错误 id {}",userBO.getId());
            throw BizException.exception("用户密码错误");
        }
        AdUserPO adUserPO=new AdUserPO();
        adUserPO.setId(userBO.getId());
        String newPwd=this.genPwd(userBO.getNewPwd(),originalUser.getSalt());
        adUserPO.setLoginPwd(newPwd);
        int c1=this.mixedDS.txDs().mapper().updateByPrimaryKeySelective(adUserPO);
        log.info("用户修改密码成功 id {} ",userBO.getId());
        return c1;
    }

    @Override
    public boolean validateLoginName(NoValidatorBO noValidatorBO) {
        AdUserPOExample example=new AdUserPOExample();
        if (StringUtils.isNotBlank(noValidatorBO.getOriginalNo())){
            if (noValidatorBO.getNewNo().equals(noValidatorBO.getOriginalNo())){
                return true;
            }
        }
        example.createCriteria().andLoginNameEqualTo(noValidatorBO.getNewNo()).andIsDelEqualTo(false);
        long c1=this.mixedDS.txDs().mapper().countByExample(example);
        if (c1==0){
            return true;
        }
        return false;
    }

    @Override
    public AdUserPO getCurrentUser() {
        Long userID=SysSession.getUser().getUserID();
        AdUserPO adUserPO=this.mixedDS.txDs().mapper().selectByPrimaryKey(AdUserPO.class,userID);
        return adUserPO;
    }

    @Override
    public AdUserPO getUserByLoginName(String loginName) {
        AdUserPOExample example=new AdUserPOExample();
        example.createCriteria().andLoginNameEqualTo(loginName);
        AdUserPO adUserPO=this.mixedDS.txDs().mapper().selectFirstByExample(example);
        return adUserPO;
    }

    @Override
    public String genPwd(String loginPwd, String salt) {
        String pwd=MD5Util.MD5(loginPwd+salt);
        return pwd;
    }

    private List<Long> getUserRoleIDList(Long userID){
        AdUserRolePOExample example=new AdUserRolePOExample();
        example.createCriteria().andUserIDEqualTo(userID);
        List<AdUserRolePO> userRolePOS=this.mixedDS.txDs().mapper().selectByExample(example);
        return userRolePOS.stream().map(AdUserRolePO::getRoleID).collect(Collectors.toList());
    }

    private List<Long> getUserAuthIDList(Long userID){
        AdUserAuthPOExample example=new AdUserAuthPOExample();
        example.createCriteria().andUserIDEqualTo(userID);
        List<AdUserAuthPO> userAuthPOS=this.mixedDS.txDs().mapper().selectByExample(example);
        return userAuthPOS.stream().map(AdUserAuthPO::getAuthID).collect(Collectors.toList());
    }
}
